package com.drm.netschool.redis;

import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Response;

/**
 * Created by CUIJB on 2015年5月13日
 */
public class RedisUtil {

	private static final Logger LOGGER = LoggerFactory.getLogger(RedisUtil.class);

	private JedisPool jedisPool;

	public JedisPool getJedisPool() {
		return this.jedisPool;
	}

	public RedisUtil(JedisPool jedisPool) {
		this.jedisPool = jedisPool;
	}

	/**
	 * 执行器 Created by CUIJB on 2015年5月7日
	 */
	abstract class Executor<T> {

		Jedis jedis;
		JedisPool jedisPool;

		public Executor(JedisPool jedisPool) {
			this.jedisPool = jedisPool;
			jedis = this.jedisPool.getResource();
		}

		/**
		 * 回调
		 * 
		 * @return 执行结果
		 */
		abstract T execute();

		/**
		 * 调用并返回执行结果 它保证在执行execute()
		 * 之后释放数据源returnResource(jedis)
		 * 
		 * @return 执行结果
		 */
		public T getResult() {
			T result = null;
			try {
				result = execute();
			} catch (Throwable e) {
				LOGGER.error("Redis execute exception", e);
				// throw new RuntimeException("Redis execute exception", e);
			} finally {
				if (jedis != null) {
					jedisPool.returnResource(jedis);
				}
			}
			return result;
		}
	}

	/**
	 * 为给定 key 设置生存时间，当 key 过期时(生存时间为 0 )，它会被自动删除。 在 Redis 中，带有生存时间的 key
	 * 被称为『可挥发』(volatile)的。
	 * 
	 * @param key
	 *            key
	 * @param expire
	 *            生命周期，单位为秒
	 * @return 1: 设置成功 0: 已经超时或key不存在
	 */
	public Long expire(final String key, final int expire) {
		return new Executor<Long>(jedisPool) {
			@Override
			Long execute() {
				return jedis.expire(key, expire);
			}
		}.getResult();
	}
	
	/** 
     * 删除 
     * @param key 匹配的key 
     * @return 删除成功的条数 
     */  
    public Long delKey(final String key) {  
        return new Executor<Long>(jedisPool) {  
            @Override  
            Long execute() {  
                return jedis.del(key);  
            }  
        }.getResult();  
    }

	/* ==========================Strings========================== */

	public String setString(final String key, final String value) {
		return new Executor<String>(jedisPool) {
			@Override
			String execute() {
				return jedis.set(key, value);
			}
		}.getResult();
	}

	public String setString(final String key, final String value, final int expire) {
		return new Executor<String>(jedisPool) {
			@Override
			String execute() {
				return jedis.setex(key, expire, value);
			}
		}.getResult();
	}

	public String getString(final String key) {
		return new Executor<String>(jedisPool) {
			@Override
			String execute() {
				return jedis.get(key);
			}
		}.getResult();
	}

	/**
	 * 进行加1操作
	 * @param key
	 * @return
	 */
	public Long stringIncr(final String key){
		return new Executor<Long>(jedisPool) {
			@Override
			Long execute() {
				return jedis.incr(key);
			}
		}.getResult();
	}
	
	public Long stringIncrBy(final String key, final long num){
		return new Executor<Long>(jedisPool) {
			@Override
			Long execute() {
				return jedis.incrBy(key, num);
			}
		}.getResult();
	}
	/* ==========================Hashes========================== */

	public Long hashSet(final String key, final String field, final String value) {
		return new Executor<Long>(jedisPool) {
			@Override
			Long execute() {
				return jedis.hset(key, field, value);
			}
		}.getResult();
	}

	public Long hashSet(final String key, final String field, final String value, final int expire) {
		return new Executor<Long>(jedisPool) {
			@Override
			Long execute() {
				Pipeline pipeline = jedis.pipelined();
				Response<Long> result = pipeline.hset(key, field, value);
				pipeline.expire(key, expire);
				pipeline.sync();
				return result.get();
			}
		}.getResult();
	}

	public String hashGet(final String key, final String field) {
		return new Executor<String>(jedisPool) {
			@Override
			String execute() {
				return jedis.hget(key, field);
			}
		}.getResult();
	}

	public String hashGet(final String key, final String field, final int expire) {
		return new Executor<String>(jedisPool) {
			@Override
			String execute() {
				Pipeline pipeline = jedis.pipelined();
				Response<String> result = pipeline.hget(key, field);
				pipeline.expire(key, expire);
				pipeline.sync();
				return result.get();
			}
		}.getResult();
	}

	public String hashMultipleSet(final String key, final Map<String, String> hash) {
		return new Executor<String>(jedisPool) {
			@Override
			String execute() {
				return jedis.hmset(key, hash);
			}
		}.getResult();
	}

	public String hashMultipleSet(final String key, final Map<String, String> hash, final int expire) {
		return new Executor<String>(jedisPool) {
			@Override
			String execute() {
				Pipeline pipeline = jedis.pipelined();
				Response<String> result = pipeline.hmset(key, hash);
				pipeline.expire(key, expire);
				pipeline.sync();
				return result.get();
			}
		}.getResult();
	}

	public List<String> hashMultipleGet(final String key, final String... fields) {
		return new Executor<List<String>>(jedisPool) {
			@Override
			List<String> execute() {
				return jedis.hmget(key, fields);
			}
		}.getResult();
	}

	public Map<String, String> hashGetAll(final String key) {
		return new Executor<Map<String, String>>(jedisPool) {

			@Override
			Map<String, String> execute() {
				return jedis.hgetAll(key);
			}
		}.getResult();
	}

	/* ==========================List========================== */

	public List<String> listGetAll(final String key) {
		return new Executor<List<String>>(jedisPool) {
			@Override
			List<String> execute() {
				return jedis.lrange(key, 0, -1);
			}
		}.getResult();
	}

	public List<String> listRange(final String key, final long beginIndex, final long endIndex) {
		return new Executor<List<String>>(jedisPool) {
			@Override
			List<String> execute() {
				return jedis.lrange(key, beginIndex, endIndex - 1);
			}
		}.getResult();
	}

	/**
	 * 将一个或多个值 value 插入到列表 key 的表头, 当列表大于指定长度是就对列表进行修剪(trim)
	 * 
	 * @param key
	 *            key
	 * @param value
	 *            string value
	 * @param size
	 *            链表超过这个长度就修剪元素
	 * @return 执行 listPushHeadAndTrim 命令后，列表的长度。
	 */
	public Long listPushHeadAndTrim(final String key, final String value, final long size) {
		return new Executor<Long>(jedisPool) {
			@Override
			Long execute() {
				Pipeline pipeline = jedis.pipelined();
				Response<Long> result = pipeline.lpush(key, value);
				// 修剪列表元素, 如果 size - 1 比 end 下标还要大，Redis将 size 的值设置为 end 。
				pipeline.ltrim(key, 0, size - 1);
				pipeline.sync();
				return result.get();
			}
		}.getResult();
	}

	public Long listPushHead(final String key, final String value) {
		return new Executor<Long>(jedisPool) {
			@Override
			Long execute() {
				return jedis.lpush(key, value);
			}
		}.getResult();
	}

	public Long listPushTail(final String key, final String... values) {
		return new Executor<Long>(jedisPool) {
			@Override
			Long execute() {
				return jedis.rpush(key, values);
			}
		}.getResult();
	}
}
